import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { app, BrowserWindow, ipcMain, dialog, shell } from 'electron'
import fs from 'node:fs'
import axios from 'axios'
import Store from 'electron-store'
import { MainAppConfig } from '../src/types/mainApp'
import { CursorPaths } from '../src/types'
import * as quitCursorUtils from './lib/quitCursorUtils'
import * as updateDisabler from './lib/disableUpdateUtils'
import { detectCursorPath } from './lib/cursorPathUtils'
import { resetMachineId } from './lib/resetMachineIdUtils'
import { injectAuthInfo } from './lib/injectCursorUtils'

// Define types directly in main process to avoid module resolution issues with renderer types.
// interface CursorPaths {
//     storage_path: string;
//     sqlite_path: string;
//     machine_id_path: string;
//     cursor_path: string;
//     updater_path: string;
//     update_yml_path: string;
//     product_json_path: string;
// }

const store = new Store();

const __dirname = path.dirname(fileURLToPath(import.meta.url))
process.env.APP_ROOT = path.join(__dirname, '..')

export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist')
export const VITE_DEV_SERVER_URL = process.env['VITE_DEV_SERVER_URL']

process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
  ? path.join(process.env.APP_ROOT, 'src', 'public')
  : RENDERER_DIST

let mainWindow: BrowserWindow | null
let updateInfo: MainAppConfig | null = null;

function createWindow(): void {
  mainWindow = new BrowserWindow({
    width: 500,
    height: 700,
    frame: false,
    resizable: false,
    show: false,
    backgroundColor: '#141414',
    webPreferences: {
      preload: path.join(__dirname, 'preload.mjs'),
      nodeIntegration: false,
      contextIsolation: true,
    },
  });

  if (VITE_DEV_SERVER_URL) {
    mainWindow.loadURL(VITE_DEV_SERVER_URL);
  } else {
    mainWindow.loadFile(path.join(RENDERER_DIST, 'index.html'));
  }

  mainWindow.on('ready-to-show', () => {
    mainWindow?.show();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  mainWindow.webContents.setWindowOpenHandler(({ url }) => {
    if (url.startsWith('https:')) shell.openExternal(url)
    return { action: 'deny' }
  });
}

async function checkForUpdates() {
  const packageJsonPath = path.join(app.getAppPath(), 'package.json');
  try {
    const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
    const localVersionCode = packageJson.version_code || 0;
    // @ts-expect-error Vite defines this global constant.
    const response = await axios.get(`${__API_URL__}/app/config`);
    const remoteConfig: MainAppConfig = response.data.data;
    updateInfo = remoteConfig;

    if (remoteConfig.version_code <= localVersionCode) {
      updateInfo = null; // No update needed
    }
  } catch (error) {
    console.error('检查更新失败:', error);
    updateInfo = null; // Ensure no update info on error
    dialog.showErrorBox('检查更新失败', '无法连接到服务器检查更新。');
  }
}

function registerIpcHandlers() {
  // --- Window Management ---
  ipcMain.on('minimize-window', (event) => {
    BrowserWindow.fromWebContents(event.sender)?.minimize()
  });

  ipcMain.on('close-window', (event) => {
    BrowserWindow.fromWebContents(event.sender)?.close()
  });

  // --- Generic Task Runner ---
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ipcMain.handle('run-task', async (event, taskName: string, ...args: any[]) => {
    const paths = store.get('cursorPaths') as Partial<CursorPaths> || {};
    
    switch (taskName) {
      // Window Management
      case 'minimizeWindow':
        BrowserWindow.fromWebContents(event.sender)?.minimize();
        return;
      case 'closeWindow':
        BrowserWindow.fromWebContents(event.sender)?.close();
        return;

      // Process Utils
      case 'quitCursor': {
        const processes = await quitCursorUtils.getCursorProcesses();
        if (processes.length === 0) {
          return { success: true, message: '没有找到正在运行的 Cursor 进程。' };
        }
        const pids = processes.map(p => p.pid);
        return quitCursorUtils.quitCursorProcesses(pids, { force: args[0] as boolean });
      }

      // Disable Auto-Update
      case 'update:check-paths': {
        const requiredPaths = ['product_json_path', 'updater_path', 'update_yml_path'];
        const missingPaths = requiredPaths.filter(p => !paths[p as keyof CursorPaths]);
        if (missingPaths.length > 0) {
          return { success: false, message: `路径不完整，请先在设置中配置 Cursor 路径。缺失: ${missingPaths.join(', ')}` };
        }
        return { success: true };
      }
      case 'update:removeUrls':
        if (!paths.product_json_path) throw new Error('Product JSON 路径未设置');
        return updateDisabler.removeUpdateUrls(paths.product_json_path);
      case 'update:removeDir':
        if (!paths.updater_path) throw new Error('Updater 路径未设置');
        return updateDisabler.removeUpdaterDirectory(paths.updater_path);
      case 'update:clearYml':
        if (!paths.update_yml_path) throw new Error('Update YML 路径未设置');
        return updateDisabler.clearUpdateYmlFile(paths.update_yml_path);
      case 'update:createBlockingFile':
        if (!paths.updater_path) throw new Error('Updater 路径未设置');
        return updateDisabler.createBlockingFile(paths.updater_path);
      case 'update:lockYml':
        if (!paths.update_yml_path) throw new Error('Update YML 路径未设置');
        return updateDisabler.lockUpdateYmlFile(paths.update_yml_path);
      
      // Update Logic
      case 'get-update-info':
        return updateInfo;
      case 'perform-update':
        if (typeof args[0] === 'string') {
          shell.openExternal(args[0]);
          app.quit();
        }
        return;

      // Store
      case 'store:get':
        return store.get(args[0]);
      case 'store:set':
        return store.set(args[0], args[1]);
      case 'store:delete':
        return store.delete(args[0]);

      // Paths
      case 'paths:get-stored':
        return store.get('cursorPaths');
      case 'paths:set-stored':
        return store.set('cursorPaths', args[0]);
      case 'paths:clear-stored':
        return store.delete('cursorPaths');
      case 'paths:auto-detect':
        return detectCursorPath();

      case 'reset-machine-id': {
        // 1. First, quit Cursor processes to ensure files are not locked.
        const processes = await quitCursorUtils.getCursorProcesses();
        if (processes.length > 0) {
          const pids = processes.map(p => p.pid);
          // Force quit is necessary before file modification.
          const quitResult = await quitCursorUtils.quitCursorProcesses(pids, { force: true, timeout: 2 });
          if (!quitResult.success) {
            // If quitting fails, we should not proceed.
            return { success: false, message: `无法在重置前关闭 Cursor 进程: ${quitResult.message}` };
          }
        }
        
        // 2. Check for required paths.
        const requiredPaths = [
          'storage_path', 
          'sqlite_path', 
          'machine_id_path',
          'cursor_path',
          'product_json_path'
        ];
        const missingPaths = requiredPaths.filter(p => !paths[p as keyof CursorPaths]);
        if (missingPaths.length > 0) {
          return { success: false, message: `路径不完整，无法重置机器码。请先在设置中配置 Cursor 路径。缺失: ${missingPaths.join(', ')}` };
        }

        // 3. Proceed with resetting the machine ID.
        await resetMachineId(paths as CursorPaths);
        return { success: true, message: '机器码已重置。在关闭相关进程后，操作已成功完成。' };
      }

      case 'account:inject': {
        const { email, token } = args[0] as { email: string; token: string };
        if (!email || !token) {
          return { success: false, message: '缺少 Email 或 Token，无法注入。' };
        }

        // 1. First, quit Cursor processes.
        const processes = await quitCursorUtils.getCursorProcesses();
        if (processes.length > 0) {
          const pids = processes.map(p => p.pid);
          // Force quit is necessary before DB modification.
          const quitResult = await quitCursorUtils.quitCursorProcesses(pids, { force: true, timeout: 2 });
          if (!quitResult.success) {
            return { success: false, message: `无法在注入前关闭 Cursor 进程: ${quitResult.message}` };
          }
        }

        // 2. Check for sqlite_path.
        if (!paths.sqlite_path) {
          return { success: false, message: '路径不完整，无法注入。请先在设置中配置 Cursor 路径。' };
        }

        // 3. Proceed with injection.
        const injectResult = await injectAuthInfo(paths.sqlite_path, { email, accessToken: token });
        
        if (injectResult.success) {
          return { success: true, message: '账号已成功注入。您可以重新启动 Cursor 查看。' };
        } else {
          return { success: false, message: injectResult.message };
        }
      }

      case 'switch-available-account': {
        const { email, token } = args[0] as { email: string; token: string };
        if (!email || !token) {
          return { success: false, message: '缺少 email 或 token 参数' };
        }

        // --- Step 1: Close Cursor processes ---
        const processes = await quitCursorUtils.getCursorProcesses();
        if (processes.length > 0) {
          const pids = processes.map(p => p.pid);
          const quitResult = await quitCursorUtils.quitCursorProcesses(pids, { force: true, timeout: 2 });
          if (!quitResult.success) {
            return { success: false, message: `步骤 1/3 失败: 无法关闭 Cursor 进程: ${quitResult.message}` };
          }
        }

        // --- Step 2: Reset Machine ID ---
        const requiredPathsForReset = [
          'storage_path', 
          'sqlite_path', 
          'machine_id_path',
          'cursor_path',
          'product_json_path'
        ];
        const missingPaths = requiredPathsForReset.filter(p => !paths[p as keyof CursorPaths]);
        if (missingPaths.length > 0) {
          return { success: false, message: `步骤 2/3 失败: 路径不完整，无法重置机器码。缺失: ${missingPaths.join(', ')}` };
        }
        
        try {
            await resetMachineId(paths as CursorPaths);
        } catch (error: unknown) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            return { success: false, message: `步骤 2/3 失败: 重置机器码时出错: ${errorMessage}`};
        }

        // --- Step 3: Inject new auth info ---
        // We know sqlite_path exists from the check above. The '!' is a non-null assertion.
        const injectResult = await injectAuthInfo(paths.sqlite_path!, { email, accessToken: token });
        if (!injectResult.success) {
            return { success: false, message: `步骤 3/3 失败: ${injectResult.message}` };
        }

        return { success: true, message: '账号已成功切换！' };
      }

      default:
        throw new Error(`未知的任务: ${taskName}`);
    }
  });
}

app.whenReady().then(() => {
  registerIpcHandlers();
  createWindow();
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
  checkForUpdates();
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});
